<script lang="ts">
    import { Input } from "../../Input";
    import { TagGroup } from "../../TagGroup";
    import { useStyle } from "../../utils/useStyle";
    import Icon from "../Icons/Icon.svelte";
    import type { ValueProps } from "./Value";

    let { query = $bindable(), ...props }: ValueProps = $props();
    let filterStr = $state("");
    let filterInput: HTMLElement | undefined = $state();
    let selection: any;
    const onClear = (e: any) => {
        e.stopImmediatePropagation && e.stopImmediatePropagation();
        e.preventDefault && e.preventDefault();
        e.stopPropagation && e.stopPropagation();
        props.onClear && props.onClear(e);
    };
    const clearable = $derived(props.clearable && props.text && (props.multi || props.range ? props.text[0]?.title && props.text[1]?.title : props.text.title));
    const classList = $derived({
        "cm-field-value": true,
        "cm-field-clearable": clearable,
        "cm-field-disabled": props.disabled,
        [`cm-field-value-${props.size}`]: !!props.size,
    });
    const text = $derived.by(() => {
        if ((props.multi || props.range) && props.text && props.text instanceof Array) {
            return props.text.map((item: any, index: number) => {
                return { id: item.id, title: props.tagRender ? props.tagRender(item) : item.title };
            });
        }
        return [];
    });

    const inputStyle = $derived.by(() => {
        // 查询内容变化时，更新输入框的宽度
        const str = props.filter ? query : "";
        updateFilterStyle();
        return useStyle(
            {},
            {
                width: "10px",
                // width: str !== undefined ? str.length * 12 + 20 + 'px' : '100%',
            }
        );
    });

    const bindEl = (el: any) => {
        filterInput = el;
        return () => {
            filterInput = undefined;
        };
    };

    const updateFilterStyle = () => {
        if (!filterInput) {
            return;
        }

        filterInput.style.width = "10px";
        filterInput.style.width = filterInput.scrollWidth + "px";

        Promise.resolve().then(() => {
            if (!filterInput) {
                return;
            }
            filterInput.style.width = "10px";
            const maxWidth = Math.floor(selection?.getBoundingClientRect().width || 10);
            filterInput.style.width = filterInput.scrollWidth + "px";
            filterInput.parentElement!.style.width = Math.min(maxWidth - 20, filterInput.scrollWidth) + "px";
        });
    };

    // 因为Input输入中文时不会触发change事件，所以需要监听input事件进行更新
    const onFilterChange = (v: string, e: any) => {
        updateFilterStyle();
        filterStr = v;
    };

    const onValueClick = () => {
        if (props.filter && filterInput) {
            filterInput.focus();
        }
    };

    const onFilterKeyDown = (e: any) => {
        const queryStr = query || "";
        if (e.key === "Backspace" || e.code === "Backspace" || e.key === "Delete" || e.code === "Delete") {
            if (queryStr.length === 0) {
                props.onDeleteLastValue && props.onDeleteLastValue();
            }
        }
    };

    const onFilterBlur = () => {
        if (props.onlyInput) {
            return;
        }
        if (props.filter) {
            filterStr = "";
            setTimeout(() => {
                query = "";
            }, 300);
        }
    };
</script>

<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class={classList} onclick={onValueClick}>
    <input type="hidden" />
    <!-- 文字对齐辅助 -->
    <span style="width: 0px; font-size: 12px; visibility: hidden; line-height: initial">A</span>
    {#if props.prepend}
        <div class="cm-field-prepend">
            {#if typeof props.prepend === "function"}
                {@render props.prepend()}
            {:else}
                {props.prepend}
            {/if}
        </div>
    {/if}
    {#if props.multi}
        <div class="cm-field-selection" bind:this={selection}>
            <TagGroup data={text} closable={props.valueClosable} max={props.showMax} showMore={props.showMore} onclose={props.onClose} size={props.size === "small" ? "small" : "large"}>
                {#snippet extra()}
                    {#if props.filter}
                        <Input
                            {@attach bindEl}
                            style={inputStyle}
                            class="cm-select-filter"
                            onblur={onFilterBlur}
                            size={props.size}
                            bind:value={query}
                            onkeydown={onFilterKeyDown}
                            oninput={onFilterChange}
                        />
                    {/if}
                {/snippet}
            </TagGroup>
            {#if !text?.length}
                <span class="cm-field-placeholder" style={`display: ${filterStr ? "none" : "inline-block"};position: absolute;z-index: 10;`}>{props.placeholder ?? ""}</span>
            {/if}
        </div>
    {:else if props.range}
        <div class="cm-field-text cm-field-range" bind:this={selection}>
            {#if text?.length}
                <span style={`display: ${filterStr ? "none" : "inline-block"}`}>
                    {text[0]?.["title"]}
                </span>
                <span>
                    <svg focusable="false" data-icon="swap-right" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024"
                        ><path d="M873.1 596.2l-164-208A32 32 0 00684 376h-64.8c-6.7 0-10.4 7.7-6.3 13l144.3 183H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h695.9c26.8 0 41.7-30.8 25.2-51.8z"></path></svg
                    >
                </span>
                <span style={`display: ${filterStr ? "none" : "inline-block"}`}>
                    {text[1]?.["title"]}
                </span>
            {:else}
                <span class="cm-field-placeholder">{props.placeholder ?? ""}</span>
            {/if}
        </div>
    {:else}
        <div class="cm-field-text" bind:this={selection}>
            {#if !props.onlyInput}
                {#if props.text}
                    <span style={`display: ${filterStr ? "none" : "inline-block"}`}>
                        {#if props.tagRender}
                            {@render props.tagRender(props.text)}
                        {:else if typeof props.text?.["title"] === "function"}
                            {@render props.text?.["title"]()}
                        {:else if props.text?.["title"]}
                            {props.text?.["title"]}
                        {:else}
                            <span class="cm-field-placeholder" style={`display: ${filterStr ? "none" : "inline-block"}`}>{props.placeholder ?? ""}</span>
                        {/if}
                    </span>
                {:else}
                    <span class="cm-field-placeholder" style={`display: ${filterStr ? "none" : "inline-block"}`}>{props.placeholder ?? ""}</span>
                {/if}
            {/if}
            {#if props.filter}
                <Input {@attach bindEl} style={inputStyle} class="cm-select-filter" size={props.size} bind:value={query} oninput={onFilterChange} onblur={onFilterBlur} />
            {/if}
        </div>
    {/if}
    <span class="cm-field-cert">
        {@render props.icon?.()}
    </span>
    {#if clearable}
        <Icon icon="xCircle" class="cm-field-clear" onclick={onClear} />
    {/if}
</div>
